﻿using Grow.Domain.DomainRepository;
using Grow.Domain.EventBus;
using Grow.EventBus.Cap.PublisherDomainEvents;
using Grow.Module.Service;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Grow.EventBus.Cap.SubscriberDomainEvents
{
    public class SubscriberDomainEventService : ISubscriberDomainEventService
    {
        private readonly IServiceContext _serviceContext;
        private readonly DomainEventBusOptions _eventBusOptions;
        private readonly IUnitOfWorkManager _unitOfWorkManager;
        private readonly ISubscriberDomainEventRepository _subscriberDomainEventRepository;
        public SubscriberDomainEventService(IServiceContext serviceContext)
        {
            _serviceContext = serviceContext;
            _eventBusOptions = _serviceContext.GetOptions<DomainEventBusOptions>();
            _unitOfWorkManager = _serviceContext.GetRequiredService<IUnitOfWorkManager>();
            _subscriberDomainEventRepository = _serviceContext.GetRequiredService<ISubscriberDomainEventRepository>();
        }

        public async Task<bool> LockSubscriberEventAsync(Guid Id, CancellationToken cancellationToken)
        {
            var now = DateTimeOffset.Now;
            var lockEndTime = DateTimeOffset.Now.AddSeconds(_eventBusOptions.LockTime);

            var unitOfWork = _unitOfWorkManager.GetUnitOfWork();

            var subscriberEventData = await _subscriberDomainEventRepository.FirstOrDefaultAsync(a =>
                 a.Id == Id
                && (a.LockEndTime < now || a.LockEndTime == null),cancellationToken);

            if (subscriberEventData is null)
            {
                return false;
            }
            subscriberEventData.LockEndTime = lockEndTime;

            await _subscriberDomainEventRepository.UpdateAsync(subscriberEventData, cancellationToken);

            await unitOfWork.CommitAsync(cancellationToken);
            return true;
        }

      

        public async Task UpdateSubscriberEventAsync(Guid Id, SubscriberDomainEventStatus subscriberDomainEventStatus, CancellationToken cancellationToken)
        {
            var unitOfWork = _unitOfWorkManager.GetUnitOfWork();

            var subscriberEvent = await _subscriberDomainEventRepository.FirstOrDefaultAsync(a =>
                a.Id == Id,cancellationToken);

            if (subscriberEvent is null)
            {
                return;
            }
            subscriberEvent.EventStatus = subscriberDomainEventStatus;
            subscriberEvent.RetryCount++;
            if (subscriberDomainEventStatus == SubscriberDomainEventStatus.Success)
            {
                subscriberEvent.ExpireTime = DateTimeOffset.Now.AddHours(_eventBusOptions.SucceedExpireHour);
            }

            await _subscriberDomainEventRepository.UpdateAsync(subscriberEvent, cancellationToken);

            await unitOfWork.CommitAsync(cancellationToken);
        }


        public async Task SaveSubscriberEventAsync(SubscriberDomainEventDto subscriberDomainEventDto, CancellationToken cancellationToken)
        {
            var unitOfWork = _unitOfWorkManager.GetUnitOfWork();

            SubscriberDomainEvent subscriberDomainEvent = new(
               subscriberDomainEventDto.Id,
               _eventBusOptions.EnvironmentName,
               subscriberDomainEventDto.EventName,
               subscriberDomainEventDto.EventType,
               subscriberDomainEventDto.EventHandlerType,
               subscriberDomainEventDto.EventBody,
               SubscriberDomainEventStatus.Wait,
               0,
               subscriberDomainEventDto.SendAt,
               null,
               null);

            await _subscriberDomainEventRepository.AddAsync(subscriberDomainEvent, cancellationToken);
            await unitOfWork.CommitAsync(cancellationToken);
        }
    }
}
